﻿using System;


namespace DailyFx.IndicatorExtension
{

    public class BOLL :  Index
    {
        /// <summary>
        /// c'tor
        /// </summary>
            public BOLL ( int span, int n )
                : base( 3, n )
            {
                // upper band
				this.UB =	new HyperVector (n, "UB", Layout.OVERLAY, Stylus.REGION	, 0 );
				// lower band												   		    
				this.LB =	new HyperVector (n, "LB", Layout.OVERLAY, Stylus.REGION	, 0 );

				this.MidMA = new HyperVector (n, "Mid", Layout.OVERLAY, Stylus.LINE, 0 );
				// % band													   
				this.Percent =	new HyperVector (n, "%B", Layout.OVERLAY, Stylus.HIDDEN	, 0); 

				// Parameters ...
				//
                if ( span <= 0 ) 
					this.Span = 20;

				this.K = 2.0m;
            }


		/// <summary>
		///		Amplifier of the bands' width .
		/// </summary>
			public decimal K = 2.0m;

		/// <summary>
		///		MA Period .
		/// </summary>
			public int Span = 20;


		public override void Cook ( BarSeries series )
		{
			SMA ma = new SMA ( Span, _length );
			ma.Cook( series);

			SMD md = new SMD(Span, _length);
			md .Cook2( ma.MAimpl);


			// Mid .
			this.MidMA  = ma.MAimpl;

			for (var n = 0; n < _length; n++ )
			{
				// try to eval the bands .
				//

				decimal sma = ma.MAimpl[n];
				decimal stddev = md.deviation[n];

				decimal U = sma + K * stddev;
				decimal L = sma - K * stddev;

				decimal pb = (sma - L) / (U - L);

				//
				this.UB[n] = U;
				this.LB[n] = L;

				this.Percent[n] = pb;
			}
		} 

		public void Cook2 ( IVector target )
		{
		}
	
		// fast method
            public  void fCook ( BarSeries series )
			{

				decimal sum = 0.0m;
				decimal sma = 0.0m;

				decimal V = 0.0m; 
				decimal stddev = 0.0m;
				decimal diff = 0.0m;

				decimal P = 0.0m;

				for (int n = 0; n < this.Length; n++)   // forming
				{
					// try to calc the MA(middle band) & stddev from previous prices .. .
					//
					decimal x = series[n].LastPx;

					sum += x;
					sum -= P;

					if (n < Span)		// still preparing 
					{
						sma = sum / (n + 1);

						if (n > 0)
						{
							diff = ((n + 1) * x) - sum;
							V += (diff * diff) / (n * (n - 1));
							stddev = Math2.Sqrt (V / n);
						}
					}
					else				// forming 
					{
                        sma = sum / Span;

                        V += (x * x) - (P * P) + (x - P - 2 * sum) / Span;
                        stddev = Math2.Sqrt(V / (Span - 1));

						P = series [n - Span].LastPx;

					}

					// try to eval the bands .
					//
					decimal U = sma + K * stddev;
					decimal L = sma - K * stddev;

					decimal pb = (x - L) / (U - L);

					//
					this.MidMA[n] = sma;

					this.UB[n]   = U;
					this.LB[n]   = L;

                    this.Percent[n] = pb;
				}

			}


            public override string Family
            {
                get { return "Bollinger Bands"; }
            }

            public override string Label
            {
                get { return "BOLL"; }
            }

         


            public HyperVector UB
            {
                get {
                    return _children[0];
                }
                private set {
                    _children[0] = value;
                }
            }

            public HyperVector LB
            {
                get {
                    return _children[1];
                }
                private set {
                    _children[1] = value;
                }
            }

			public HyperVector MidMA
			{
				get {
					return _children[2];
				}
				private set {
					_children[2] = value;
				}
			}

            public HyperVector Percent
            {
                get {
                    return _children[3];
                }
                private set {
                    _children[3] = value;
                }
            }

	} // ks BOLL

} // 
